package edu.yngsxy.communityservice.sys.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.crypto.digest.BCrypt;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import edu.yngsxy.communityservice.core.exception.BusinessException;
import edu.yngsxy.communityservice.core.model.dto.LoginDTO;
import edu.yngsxy.communityservice.core.model.dto.RegisterDTO;
import edu.yngsxy.communityservice.sys.dao.SysRoleMapper;
import edu.yngsxy.communityservice.sys.dao.SysUserRoleMapper;
import edu.yngsxy.communityservice.sys.model.dto.SysUserDTO;
import edu.yngsxy.communityservice.sys.model.entity.SysRole;
import edu.yngsxy.communityservice.sys.model.entity.SysUser;
import edu.yngsxy.communityservice.sys.dao.SysUserMapper;
import edu.yngsxy.communityservice.sys.model.entity.SysUserRole;
import edu.yngsxy.communityservice.sys.service.SysUserService;
import edu.yngsxy.communityservice.core.service.impl.WkBaseServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.function.Consumer;

/**
 * <p>
 * 用户：存储系统用户信息 服务实现类
 * </p>
 *
 * @author lr
 * @since 2025-09-09
 */
@Service
public class SysUserServiceImpl extends WkBaseServiceImpl<SysUserMapper, SysUser> implements SysUserService {

    @Autowired
    private SysRoleMapper sysRoleMapper;
    @Autowired
    private SysUserRoleMapper sysUserRoleMapper;
    @Autowired
    private SysUserMapper sysUserMapper;
    @Transactional(rollbackFor = BusinessException.class)// 事务注解
    @Override
    public SysUser register(RegisterDTO registerDTO, Consumer<SysUser> beforeSaveCallback) {
        // 1. 检查用户名是否已存在
        SysUser existingUser = findByUsername(registerDTO.getUsername());
        if (existingUser != null) {
            throw new BusinessException("用户名已被注册");
        }
        //2. 检查角色是否存在
        SysRole role = sysRoleMapper.selectOne(new LambdaQueryWrapper<SysRole>().eq(SysRole::getCode, registerDTO.getRole()), false);
        if (role==null) {
            throw new RuntimeException(String.format("角色%s不存在", registerDTO.getRole()));
        }
        // 3. 检查邮箱是否已存在
        if (findByEmail(registerDTO.getEmail()) != null) {
            throw new BusinessException("邮箱已被注册");
        }
        // 4. 密码加密 - 使用BCrypt算法
        String encryptedPassword = BCrypt.hashpw(registerDTO.getPassword(), BCrypt.gensalt(12));

        // 5. 构建用户对象
        SysUser user = new SysUser();
        //对象复制 Hutool（底层反射带缓存，性能中等） vs Spring BeanUtils（底层反射不带缓存，性能较差） vs MapStruct（编译期生成 getter/setter，性能最优（接近手写）） 对比
        BeanUtil.copyProperties(registerDTO, user); // 复制所有同名同类型属性
        user.setPassword(encryptedPassword);// 加密后的密码
        user.setAddedTime(LocalDateTime.now());// 设置注册时间
        if (beforeSaveCallback!= null) {// 保存之前，执行回调函数
            beforeSaveCallback.accept(user);
        }
        // 6. 保存用户信息到数据库
        int rows = baseMapper.insert(user);
        // 7. 保存用户角色关系
        sysUserRoleMapper.insert(new SysUserRole().setUserId(user.getId()).setRoleId(role.getId()));
        // 8. 保存用户角色关系失败
        if (rows <= 0) {
            throw new BusinessException("注册失败，请稍后重试");
        }
        return user;
    }
    public SysUser findByUsername(String username) {
        return baseMapper.selectOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUsername, username));
    }
    public SysUser findByEmail(String email) {
        return baseMapper.selectOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getEmail, email));
    }

    /**
     * 处理用户登录逻辑
     */
    @Override
    public SysUser login(LoginDTO loginDTO) {
        // 1. 根据用户名查询用户
        SysUser user = findByUsername(loginDTO.getUsername());// 根据用户名查询用户
        if (user == null) {
            throw new BusinessException("用户名不存在！");
        }

        // 2. 验证密码（BCrypt加密验证）
        boolean passwordMatch = BCrypt.checkpw(loginDTO.getPassword(), user.getPassword());
        if (!passwordMatch) {
            throw new BusinessException("密码错误！");
        }

        // 6. 记录登录日志（实际项目中可添加）
        //recordLoginLog(user.getId(), request.getRemoteAddr());
        return user;
    }

    @Override
    public SysUserDTO selectWithRolePermissionByUserId(Long userId) {
        return baseMapper.selectWithRolePermissionByUserId(userId);
    }

    /**
     * 动态更新用户（仅更新非空字段，空密码时保留原密码）
     */
    @Override
    public boolean updateUserSelective(SysUser user) {
        // 若密码为空，查询原密码并赋值
        if (user.getPassword() == null || user.getPassword().isEmpty()) {
            SysUser oldUser = baseMapper.selectById(user.getId());
            user.setPassword(oldUser.getPassword());
        } else {
            // 若传了新密码，先加密
            user.setPassword(BCrypt.hashpw(user.getPassword(), BCrypt.gensalt(12)));
        }
        // 执行动态更新
        int rows = sysUserMapper.updateUserSelective(user);
        return rows > 0;
    }


}
